using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Gko.Utils.Interfaces;

namespace Gko.Utils
{
	internal class PropertyBinding<TBindable, TProperty> where TBindable : IBindable
	{
		private readonly BindableProperty<TBindable, TProperty> sourceProperty;
		private readonly Action<TBindable, TProperty> setter;

		internal PropertyBinding(BindableProperty<TBindable, TProperty> sourceProperty, string destinationPropertyName, Func<TProperty, object> converter)
			: this(sourceProperty, GetDestintionProperty(destinationPropertyName, converter))
		{
		}

		internal PropertyBinding(BindableProperty<TBindable, TProperty> sourceProperty, Action<TBindable, TProperty> setter)
		{
			this.sourceProperty = sourceProperty;
			this.setter = setter;
		}

		private static Action<TBindable, TProperty> GetDestintionProperty(string destinationPropertyName, Func<TProperty, object> converter)
		{
			var property = typeof(TBindable).GetProperty(destinationPropertyName, BindingFlags.Public | BindingFlags.Instance);
			if (!property.CanWrite) {
				throw new InvalidOperationException(String.Format("Property '{0}' does not have setter", destinationPropertyName));
			}
			var setMethod = property.GetSetMethod();
			return (b, v) => setMethod.Invoke(b, new[] { converter(v) });
		}

		internal void UpdateDestination(TBindable source, TProperty value)
		{
			this.setter(source, value);
		}
	}
}